use crate::model::{SpadesModel, SpadesState, CARDH, CARDW};
use tge::{
    context::Context,
    event::{event_check, event_register},
    game::{Model, Render},
    render::sprite::{Sprite, Sprites},
    render::style::{Color, Style},
    render::terminal::Term,
};

pub struct SpadesRender {
    pub term: Term,
    pub sprites: Sprites,
    pub cards: Vec<Sprite>,
}

const POS_ADJ: [[u16; 2]; 4] = [[12u16, 20], [0, 10], [30, 0], [70, 10]];

impl SpadesRender {
    pub fn new() -> Self {
        //把54张牌img存储在bs中,bs[tile_num - 1]可访问到对应牌图形
        let mut bs: Vec<Sprite> = vec![];
        for i in 0..=54 {
            let mut ts = Sprite::new(0, 0, CARDW as u16, CARDH as u16);
            let cn = if i == 0 {
                format!("assets/poker/back.txt")
            } else {
                format!("assets/poker/{}.txt", i)
            };
            ts.load_esc(&cn, 0, 0);
            bs.push(ts);
        }

        let t = Term::new();
        let mut s = Sprites::new("main");

        let gb = Sprite::new(0, 0, 80, 25);
        // gb.load_esc("assets/redblack/back.txt", 0, 0);
        s.add_by_tag(gb, "back");

        // 13张手牌
        for i in 0..13 {
            s.add_by_tag(
                Sprite::new(0, 0, CARDW as u16, CARDH as u16),
                &format!("t{}", i),
            );
        }

        // 机器人的手牌
        for i in 0..4 {
            s.add_by_tag(Sprite::new(0, 0, 16, 1), &format!("current{}", i));
            s.add_by_tag(Sprite::new(0, 0, 16, 1), &format!("bid{}", i));
            s.add_by_tag(Sprite::new(0, 0, 16, 1), &format!("trick{}", i));
            s.add_by_tag(Sprite::new(0, 0, 16, 1), &format!("cards{}", i));
            if i > 0 {
                for j in 0..3 {
                    s.add_by_tag(
                        Sprite::new(0, 0, CARDW as u16, CARDH as u16),
                        &format!("robot_t{}{}", i - 1, j),
                    );
                }
            }
        }

        // 屏幕中间主信息
        s.add_by_tag(
            Sprite::new(34, 12, CARDW as u16 * 5, CARDH as u16),
            "main_msg",
        );

        // 桌面本轮牌
        for i in 0..4 {
            s.add_by_tag(
                Sprite::new(0, 0, CARDW as u16, CARDH as u16),
                &format!("turn{}", i),
            );
        }

        let isc = [
            "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E",
        ];
        for i in 0..=13 {
            let mut is = Sprite::new(0, 0, 1, 1);
            is.content
                .set_str(0, 0, isc[i], Style::default().fg(Color::Cyan));
            is.set_hidden(true);
            s.add_by_tag(is, &format!("is{}", i));
        }

        event_register("Spades.RedrawTile", "redraw_tile");
        event_register("Spades.RedrawMsg", "redraw_msg");
        event_register("Spades.RedrawTurn", "redraw_turn");

        Self {
            term: t,
            sprites: s,
            cards: bs,
        }
    }

    pub fn redraw_turn<G: Model>(&mut self, _ctx: &mut Context, model: &mut G) {
        let md = model.as_any().downcast_mut::<SpadesModel>().unwrap();
        let d = &md.round;
        for i in 0..4 {
            let hc = self.sprites.get_by_tag(&format!("turn{}", i));
            hc.set_pos(POS_ADJ[i][0], POS_ADJ[i][1] + 6);
            hc.set_hidden(true);
        }
        let turns = &d.turns;
        if turns.len() == 0 {
            return;
        }
        let mut turn_cards = &d.cur_turn().turn_cards; if turns.len() > 1 && turn_cards.len() == 0 {
            turn_cards = &turns[turns.len() - 2].turn_cards;
        }
        // let turn_cards = &d.cur_turn().turn_cards;
        for o in turn_cards {
            let hc = self.sprites.get_by_tag(&format!("turn{}", o.seat_id));
            hc.copy_content(&self.cards[o.card.to_u8() as usize]);
            hc.set_hidden(false);
        }
    }

    pub fn redraw_msg<G: Model>(&mut self, ctx: &mut Context, model: &mut G) {
        let md = model.as_any().downcast_mut::<SpadesModel>().unwrap();
        let d = &md.round;
        let l = self.sprites.get_by_tag("main_msg");
        match ctx.state.into() {
            SpadesState::Dealing => {
                l.content.dstr("dealing...");
            }
            SpadesState::Bidding => {
                l.content.dstr("bidding...");
            }
            SpadesState::Playing => {
                if d.spades_break {
                    l.content.dstr("playing(BREAK)...");
                } else {
                    l.content.dstr("playing...");
                }
            }
            SpadesState::Billing => {
                l.content.dstr("billing...        ");
            }
        }
        for i in 0..4 {
            let mut mb = self.sprites.get_by_tag(&format!("current{}", i));
            if d.seats[i].bid == None {
                mb.content.dstr(&format!("bid: none    "));
            } else {
                mb.content.dstr(&format!("bid:{:?}    ", d.seats[i].bid.unwrap()));
            }
            mb.set_pos(POS_ADJ[i][0] + 2, POS_ADJ[i][1] + 5);

            mb = self.sprites.get_by_tag(&format!("bid{}", i));
            if d.current_seat_id == i {
                mb.content.dstr(&format!("🍎"));
            } else {
                mb.content.dstr(&format!(" "));
            }
            mb.set_pos(POS_ADJ[i][0], POS_ADJ[i][1] + 5);

            mb = self.sprites.get_by_tag(&format!("trick{}", i));
            mb.content.dstr(&format!("trick:{}    ", d.seats[i].tricks));
            mb.set_pos(POS_ADJ[i][0] + 11, POS_ADJ[i][1] + 5);

            mb = self.sprites.get_by_tag(&format!("cards{}", i));
            mb.content.dstr(&format!("card:{}    ", d.seats[i].cards.cards.len()));
            mb.set_pos(POS_ADJ[i][0] + 21, POS_ADJ[i][1] + 5);
        }
    }

    pub fn redraw_tile<G: Model>(&mut self, _context: &mut Context, model: &mut G) {
        let md = model.as_any().downcast_mut::<SpadesModel>().unwrap();
        let d = &md.round;
        let sc = &d.seats[0].cards;
        let sc_can = &d.seats[0].cards_can;
        let mut label_idx = 0usize;
        for i in 0..=13 {
            let lis = self.sprites.get_by_tag(&format!("is{}", i));
            lis.set_hidden(true);
        }
        for i in 0..13 {
            let l = self.sprites.get_by_tag(&format!("t{}", i));

            if i + 1 > sc.cards.len() {
                l.set_hidden(true);
                continue;
            }
            let cd = sc.cards[i];
            l.copy_content(&self.cards[cd.to_u8() as usize]);
            let x = (i * (CARDW - 3)) as u16 + 1u16;
            l.set_pos(x + POS_ADJ[0][0], POS_ADJ[0][1]);
            if sc_can.contain(cd) {
                // 取出对应的is label
                let lis = self.sprites.get_by_tag(&format!("is{}", label_idx + 1));
                lis.set_hidden(false);
                lis.set_pos(
                    POS_ADJ[0][0] + 3 + (i as u16 * (CARDW as u16 - 3)),
                    POS_ADJ[0][1] - 1,
                );
                label_idx += 1;
            }
        }
        for i in 0..3 {
            for j in 0..3 {
                let l = self.sprites.get_by_tag(&format!("robot_t{}{}", i, j));
                l.copy_content(&self.cards[0]);
                let x = (j * (CARDW - 3)) as u16 + 1u16;
                l.set_pos(x + POS_ADJ[i + 1][0], POS_ADJ[i + 1][1]);
            }
        }
    }
}

impl Render for SpadesRender {
    fn init(&mut self, context: &mut Context) {
        context.adapter.init(120, 35, 1.0, 1.0, "spades".to_string());
        self.term.init(context);
    }

    fn handle_event<G: Model>(&mut self, context: &mut Context, data: &mut G, _dt: f32) {
        if event_check("Spades.RedrawTile", "redraw_tile") {
            self.redraw_tile(context, data);
        }
        if event_check("Spades.RedrawMsg", "redraw_msg") {
            self.redraw_msg(context, data);
        }
        if event_check("Spades.RedrawTurn", "redraw_turn") {
            self.redraw_turn(context, data);
        }
    }

    fn handle_timer<G: Model>(&mut self, _context: &mut Context, _model: &mut G, _dt: f32) {}

    fn draw<G: Model>(&mut self, ctx: &mut Context, _data: &mut G, _dt: f32) {
        self.term
            .draw(ctx, |f| {
                self.sprites.render_all(f);
            })
            .unwrap();
    }
}
